/*
 * Copyright (C) 2010 Enrique Lara (enrique.posix2.lara@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package app.tellwmata;

import android.app.DatePickerDialog;

import android.app.DatePickerDialog.OnDateSetListener;

import android.app.Dialog;
import android.app.TimePickerDialog;

import android.content.SharedPreferences;

import android.os.Bundle;

import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;

import android.preference.Preference.OnPreferenceChangeListener;

import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;

import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TimePicker;
import static app.tellwmata.Constants.FormFields.BUS_NUMBER;
import static app.tellwmata.Constants.FormFields.BUS_ROUTE_NUMBER;
import static app.tellwmata.Constants.FormFields.CATEGORY;
import static app.tellwmata.Constants.FormFields.COMMENTS;
import static app.tellwmata.Constants.FormFields.DESTINATION;
import static app.tellwmata.Constants.FormFields.EMAIL;
import static app.tellwmata.Constants.FormFields.FIRST_NAME;
import static app.tellwmata.Constants.FormFields.FORM;
import static app.tellwmata.Constants.FormFields.FORM_TYPE;
import static app.tellwmata.Constants.FormFields.INCIDENT_ADDRESS;
import static app.tellwmata.Constants.FormFields.INCIDENT_CITY;
import static app.tellwmata.Constants.FormFields.INCIDENT_STATE;
import static app.tellwmata.Constants.FormFields.INCIDENT_TYPE;
import static app.tellwmata.Constants.FormFields.LAST_NAME;
import static app.tellwmata.Constants.FormFields.RAIL_CAR_NUMBER;
import static app.tellwmata.Constants.FormFields.RAIL_LINE;
import static app.tellwmata.Constants.FormFields.STATION;
import static app.tellwmata.Constants.FormFields.TOPIC;
import static app.tellwmata.Constants.FormFields.TYPE;
import static app.tellwmata.Constants.TYPE_BUS;
import static app.tellwmata.Constants.TYPE_METRO;
import static app.tellwmata.Constants.TYPE_PARATRANSIT;

import app.tellwmata.model.Agency;

import java.util.Calendar;
import java.util.HashMap;

public final class FormEditor extends PreferenceActivity {
    public static final int MENU_ITEM_SEND = Menu.FIRST;
    public static final int MENU_ITEM_DISCARD = Menu.FIRST + 1;
    private static final int MENU_ITEM_SEND_AND_TWEET = Menu.FIRST + 2;
    private HashMap<String, String> formCfg;
    private HashMap<String, String> form;
    private SharedPreferences prefs;
    private Agency agency;
    private static final int DIALOG_DATE = 1;
    private static final int DIALOG_TIME = 2;
    private static final String DATE_FORMAT = "(MM/dd/yyyy)";
    private int routeType;
    private Preference datePref;
    private Preference timePref;
    protected int year;
    protected int monthOfYear;
    protected int dayOfMonth;
    protected int hourOfDay;
    protected int minute;
    String formType;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Bundle extras = getIntent().getExtras();
        final String formName = extras.getString(Constants.FormFields.FORM_NAME);
        routeType = extras.getInt(Constants.FormFields.ROUTE_TYPE);

        agency = Agency.getInstance(this);
        prefs = PreferenceManager.getDefaultSharedPreferences(this);

        formCfg = agency.getFormCfg(formName, routeType);
        formType = formCfg.get(FORM_TYPE);

        initForm();

        Calendar c = Calendar.getInstance();
        year = c.get(Calendar.YEAR);
        monthOfYear = c.get(Calendar.MONTH);
        dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
        hourOfDay = c.get(Calendar.HOUR_OF_DAY);
        minute = c.get(Calendar.MINUTE);

        setPreferenceScreen(createPreferenceHierarchy());

        updateDate();
        updateTime();

        initTitle(extras, formName);

        setContentView(R.layout.form_edit);

        Button b = (Button) findViewById(R.id.submit_to_agency);
        b.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendForm();
                }
            });
        b = (Button) findViewById(R.id.submit_to_agency_and_twitter);
        b.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendAndTweetForm();
                }
            });
        b = (Button) findViewById(R.id.cancel);
        b.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    FormEditor.this.finish();
                }
            });
    }

    private void initTitle(final Bundle extras, final String formName) {
        final String focus;

        if (extras.containsKey("title")) {
            focus = extras.getString("title");
        } else {
            focus = formName;
        }

        switch (routeType) {
            case TYPE_BUS:
                setTitle(getString(R.string.buses) + " - " + focus);

                break;

            case TYPE_METRO:
                setTitle(getString(R.string.metro) + " - " + focus);

                break;

            case TYPE_PARATRANSIT:
                setTitle(getString(R.string.paratransit) + " - " + focus);

                break;

            default:
                setTitle(focus);

                break;
        }
    }

    private HashMap<String, String> initForm() {
        form = new HashMap<String, String>();

        for (int i = 0; i < FORM.length; i++) {
            final String field = FORM[i];

            if (formCfg.containsKey(field)) {
                final String value = formCfg.get(field);

                if ("PROMPT".equals(value)) {
                    continue;
                } else if ("NA".equals(value)) {
                    continue;
                } else if ("PREF".equals(value)) {
                    if (prefs.contains(field)) {
                        form.put(field, prefs.getString(field, ""));
                    }
                } else {
                    form.put(field, value);
                }
            }
        }

        return new HashMap<String, String>();
    }

    private class FormOnPreferenceChangeListener implements OnPreferenceChangeListener {
        private final String fieldName;

        public FormOnPreferenceChangeListener(String fieldName) {
            this.fieldName = fieldName;
        }

        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            String s = newValue.toString();
            form.put(fieldName, s);
            preference.setSummary(s);

            return true;
        }
    }

    private PreferenceScreen createPreferenceHierarchy() {
        PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this);

        if (doPrompt(TYPE)) {
            addListPref(root, TYPE, R.string.type, R.array.TypeNames, R.array.TypeVals);
        }

        if (doPrompt(CATEGORY)) {
            addListPref(root, CATEGORY, R.string.Category, R.array.CategoryNames, R.array.CategoryVals);
        }

        if (doPrompt(TOPIC)) {
            addListPref(root, TOPIC, R.string.Topic, R.array.TopicNames, R.array.TopicVals);
        }

        if (doPrompt(INCIDENT_TYPE)) {
            addListPref(root, INCIDENT_TYPE, R.string.IncidentType, R.array.IncidentTypeNames, R.array.IncidentTypeVals);
        }

        if (doPrompt(FIRST_NAME)) {
            addTextPref(root, FIRST_NAME, R.string.FirstName);
        }

        if (doPrompt(LAST_NAME)) {
            addTextPref(root, LAST_NAME, R.string.LastName);
        }

        if (doPrompt(EMAIL)) {
            addTextPref(root, EMAIL, R.string.EmailAddress);
        }

        // Always prompt for date and time.
        datePref = new Preference(this);
        datePref.setTitle(R.string.DateOfIncident);
        root.addPreference(datePref);

        timePref = new Preference(this);
        timePref.setTitle(R.string.TimeOfIncident);
        root.addPreference(timePref);

        if (doPrompt(BUS_ROUTE_NUMBER)) {
            if (this.routeType == TYPE_BUS) {
                final String[] busRoutes = agency.getBusRoutes();
                ListPreference listPref = new ListPreference(this);
                listPref.setEntries(busRoutes);
                listPref.setEntryValues(busRoutes);
                listPref.setDialogTitle(R.string.RouteNumber);
                listPref.setKey(BUS_ROUTE_NUMBER);
                listPref.setTitle(R.string.RouteNumber);
                listPref.setOnPreferenceChangeListener(new FormOnPreferenceChangeListener(BUS_ROUTE_NUMBER));
                root.addPreference(listPref);
            } else {
                addTextPref(root, BUS_ROUTE_NUMBER, R.string.RouteNumber);
            }
        }

        if (doPrompt(BUS_NUMBER)) {
            addTextPref(root, BUS_NUMBER, R.string.BusNumber);
        }

        if (doPrompt(RAIL_LINE)) {
            addListPref(root, RAIL_LINE, R.string.RailLine, R.array.RailLineNames, R.array.RailLineVals);
        }

        if (doPrompt(RAIL_CAR_NUMBER)) {
            addTextPref(root, RAIL_CAR_NUMBER, R.string.RailCarNumber);
        }

        if (doPrompt(STATION)) {
            addListPref(root, STATION, R.string.Station, R.array.StationNames, R.array.StationVals);
        }

        if (doPrompt(DESTINATION)) {
            //XXX Check rail_line to set options. 
            addTextPref(root, DESTINATION, R.string.Destination);
        }

        if (doPrompt(INCIDENT_ADDRESS)) {
            addTextPref(root, INCIDENT_ADDRESS, R.string.Incident_Address1);
        }

        if (doPrompt(INCIDENT_CITY)) {
            addTextPref(root, INCIDENT_CITY, R.string.Incident_City);
        }

        if (doPrompt(INCIDENT_STATE)) {
            addListPref(root, INCIDENT_STATE, R.string.Incident_State, R.array.IncidentStateNames, R.array.IncidentStateVals);
        }

        if (doPrompt(COMMENTS)) {
            //XXX In form submission, this will be "additional" comments.
            //XXX For first line, get template from string.xml, apply as format, if available.
            addTextPref(root, COMMENTS, R.string.Comments);
        }

        return root;
    }

    private void addTextPref(PreferenceScreen root, String fieldName, final int titleId) {
        EditTextPreference txtPref = new EditTextPreference(this);
        txtPref.setKey(fieldName);
        txtPref.setTitle(titleId);
        txtPref.setOnPreferenceChangeListener(new FormOnPreferenceChangeListener(fieldName));
        txtPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    preference.setSummary(newValue.toString());

                    return true;
                }
            });

        if (form.containsKey(fieldName)) {
            txtPref.setText(form.get(fieldName));
            txtPref.setSummary(form.get(fieldName));
        }

        root.addPreference(txtPref);
    }

    private void addListPref(PreferenceScreen root, final String fieldName, final int titleId, final int namesId, final int valuesId) {
        ListPreference listPref = new ListPreference(this);
        listPref.setEntries(namesId);
        listPref.setEntryValues(valuesId);
        listPref.setDialogTitle(titleId);
        listPref.setKey(fieldName);
        listPref.setTitle(titleId);
        listPref.setOnPreferenceChangeListener(new FormOnPreferenceChangeListener(fieldName));

        if (form.containsKey(fieldName)) {
            Android.updateListPrefSummary(listPref, form.get(fieldName));
        }

        listPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    Android.updateListPrefSummary((ListPreference) preference, newValue.toString());

                    return true;
                }
            });

        if (form.containsKey(fieldName)) {
            listPref.setValue(form.get(fieldName));
        }

        root.addPreference(listPref);
    }

    private boolean doPrompt(String field) {
        if (formCfg.containsKey(field)) {
            final String value = formCfg.get(field);

            if ("PROMPT".equals(value)) {
                return true;
            } else if ("PREF".equals(value)) {
                return !form.containsKey(field) || (form.get(field).trim().length() == 0);
            } else if ("NA".equals(value)) {
                return false;
            }
        }

        return false;
    }

    @Override
    public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen, final Preference preference) {
        if (preference == datePref) {
            showDialog(DIALOG_DATE);
        } else if (preference == timePref) {
            showDialog(DIALOG_TIME);
        }

        return super.onPreferenceTreeClick(preferenceScreen, preference);
    }

    private void updateDate() {
        datePref.setSummary(getDateStr());
    }

    private CharSequence getDateStr() {
        final Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, monthOfYear);
        c.set(Calendar.DAY_OF_MONTH, dayOfMonth);

        return android.text.format.DateFormat.format(DATE_FORMAT, c);
    }

    private void updateTime() {
        timePref.setSummary(getTimeStr());
    }

    private static final String T12 = "h:mm aa";
    private static final String T24 = "kk:mm";

    private CharSequence getTimeStr() {
        final Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
        c.set(Calendar.MINUTE, minute);

        String format = android.text.format.DateFormat.is24HourFormat(this) ? T24 : T12;

        return android.text.format.DateFormat.format(format, c);
    }

    protected Dialog onCreateDialog(final int id) {
        switch (id) {
            case DIALOG_DATE:

                DatePickerDialog d = new DatePickerDialog(this, new OnDateSetListener() {
                        @Override
                        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                            FormEditor.this.year = year;
                            FormEditor.this.monthOfYear = monthOfYear;
                            FormEditor.this.dayOfMonth = dayOfMonth;
                            updateDate();
                        }
                    }, year, monthOfYear, dayOfMonth);
                d.setTitle(R.string.DateOfIncident);

                return d;

            case DIALOG_TIME:

                TimePickerDialog t = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
                        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                            FormEditor.this.hourOfDay = hourOfDay;
                            FormEditor.this.minute = minute;
                            updateTime();
                        }
                    }, hourOfDay, minute, android.text.format.DateFormat.is24HourFormat(this));
                t.setTitle(R.string.TimeOfIncident);

                return t;
        }

        return null;
    }

    @Override
    public final boolean onCreateOptionsMenu(final Menu menu) {
        super.onCreateOptionsMenu(menu);

        menu.add(0, MENU_ITEM_SEND, 0, R.string.submit_to_agency).setShortcut('1', 's').setIcon(android.R.drawable.ic_menu_send);
        menu.add(0, MENU_ITEM_SEND_AND_TWEET, 1, R.string.submit_to_agency_and_twitter).setShortcut('2', 't').setIcon(android.R.drawable.ic_menu_send);
        menu.add(0, MENU_ITEM_DISCARD, 2, R.string.cancel).setShortcut('3', 'd').setIcon(android.R.drawable.ic_menu_delete);

        return true;
    }

    @Override
    public final boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case MENU_ITEM_SEND:
                sendForm();

                return true;

            case MENU_ITEM_SEND_AND_TWEET:
                sendAndTweetForm();

                return true;

            case MENU_ITEM_DISCARD:
                finish();

                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void sendAndTweetForm() {
        agency.sendTwitter(formType, routeType, form);
        sendForm();
    }

    private void sendForm() {
        final Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, monthOfYear);
        c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
        c.set(Calendar.MINUTE, minute);

        if (agency.submitRiderForm(formType, routeType, c, form)) {
//XXX			
        }

        finish();
    }
}
